﻿using System;
using System.Collections.Generic;
using DataInterpolator.Model;
using OxyPlot;

namespace DataInterpolator.Design
{
   public class DesignDataService : IDataService
   {
      public static void GenerateDataSets(int count, Action<IList<DataPoint>, IList<DataPoint>> callback)
      {
         List<double> movement = GenerateMovement(count);

         var leftX = VaryXValues(0.0, 5.0, count, 0.1);
         var leftY = VaryYValues(0.0, movement, 0.0);

         var rightX = VaryXValues(0.0, 5.0, count, 0.5);
         var rightY = VaryYValues(0.0, movement, 1.0);

         callback(CombineXY(-1.0, leftX, 10.0, leftY), CombineXY(-1.0, rightX, 10.0, rightY));
      }

      private static Random _Rand = new Random();

      private static List<double> GenerateMovement(int count)
      {
         double maxValue = 1.0;
         double minValue = -1.0;
         double range = maxValue - minValue;
         List<double> values = new List<double>();

         double maxMove = range * 0.1;

         double prevValue = 0.0;

         for (int i = 0; i < count; i++)
         {
            maxMove = 0.5;

            for (int j = values.Count - 1; j >= 0 && j > values.Count - 5; j--)
            {
               maxMove -= Math.Abs(values[j]) / range;
            }

            maxMove = Math.Max(maxMove, 0.05);

            double scale = (prevValue > 0) ? 1.1 : .9;

            double move = (_Rand.NextDouble() * range) - (prevValue - minValue);
            move *= maxMove;

            double nextValue = prevValue + move;
            nextValue = Math.Max(nextValue, minValue);
            nextValue = Math.Min(nextValue, maxValue);

            move = nextValue - prevValue;

            values.Add(move);

            prevValue = nextValue;
         }

         return values;
      }

      private static IList<double> VaryYValues(double startValue, List<double> movement, double variance)
      {
         List<double> set = new List<double>();

         double prevValue = startValue;

         for (int i = 0; i < movement.Count; i++)
         {
            double move = (_Rand.NextDouble() * variance) + (1.0 - variance / 2.0);
            move *= movement[i];

            prevValue += move;
            prevValue = Math.Max(prevValue, -1.0);
            prevValue = Math.Min(prevValue, 1.0);

            set.Add(prevValue);
         }

         return set;
      }

      private static IList<double> VaryXValues(double startValue, double increment, int count, double variance)
      {
         List<double> set = new List<double>();

         double prevValue = startValue;

         for (int i = 0; i < count; i++)
         {
            double move = (_Rand.NextDouble() * variance) + (1.0 - variance / 2.0);
            move *= increment;

            prevValue += move;

            set.Add(prevValue);
         }

         return set;
      }

      private static IList<DataPoint> CombineXY(double xScale, IList<double> x, double yScale, IList<double> y)
      {
         List<DataPoint> points = new List<DataPoint>();

         for (int i = 0; i < x.Count; i++)
         {
            points.Add(new DataPoint(xScale * x[i], yScale * y[i]));
         }

         return points;


      }

      public event Action InterpolatedValuesUpdated;
      public event Action<IList<string>, string> LeftFileColumnsUpdated;
      public event Action<IList<string>, string> RightFileColumnsUpdated;
      public event Action<string> StatusMessage;
      public event Action<PartialUpdateTypes> WellDataUpdated;

      public void GetInterpolatedValues(Action<DataSet, IList<DataSet>, DataSet, double, double> callback)
      {
         GenerateDataSets(100, (left, right) =>
         {
            //callback(left, null, right);
         });
      }

      public void SetInterpolationLevels(int levelCount)
      {
         
      }

      public void SetInterpolationPairs(IList<InterpPair> pairs)
      {
         
      }

      public void SetLeftFile(string filename)
      {
         
      }

      public void SetLeftFileColumn(string columnName)
      {
         
      }

      public void SetRightFile(string filename)
      {
         
      }

      public void SetRightFileColumn(string columnName)
      {
         
      }

      public void SetSamplingDistance(double distanceFeet)
      {
         
      }

      public void ImportLogFiles(IList<string> fileNames)
      {
         throw new NotImplementedException();
      }

      public void GetWellData(Action<IList<Well>> callback)
      {
         throw new NotImplementedException();
      }

      public void SaveDatabaseFile(string filename)
      {
         throw new NotImplementedException();
      }

      public bool LoadDatabaseFile(string filename)
      {
         throw new NotImplementedException();
      }

      public void NewDatabase()
      {
         throw new NotImplementedException();
      }

      public string SaveDatabaseFile(bool showDialog)
      {
         throw new NotImplementedException();
      }

      public void SetTopFormation(string topFormationTitle)
      {
         throw new NotImplementedException();
      }

      public void SetBotFormation(string botFormationTitle)
      {
         throw new NotImplementedException();
      }

      public void SetInterpWells(string left, string right)
      {
         throw new NotImplementedException();
      }

      public void SetLeftWell(string wellTitle)
      {
         throw new NotImplementedException();
      }

      public void SetRightWell(string wellTitle)
      {
         throw new NotImplementedException();
      }

      public bool UnsavedChanges()
      {
         throw new NotImplementedException();
      }

      public void RemoveWells(IList<Guid> wellIDs)
      {
         throw new NotImplementedException();
      }

      public void UpdateWell(Guid id, Func<Well, bool> callback)
      {
         throw new NotImplementedException();
      }

      public bool SetZeroRef(string refPoint)
      {
         throw new NotImplementedException();
      }

      public bool SetWindow(double minValue, double maxValue)
      {
         throw new NotImplementedException();
      }

      public bool ExportInterpolation(ExportInterpInfo exportInfo)
      {
         throw new NotImplementedException();
      }
   }
}